// Filename: util.rs

// use std::ptr;
use core::ptr;
// Rust does not allow overlapping mutable references, so
// there is no need to worry about overlapping issues.

/// Replaces each byte in the specified memory range with `ch`.
pub fn memset(dst: &mut [u8], ch: u8) {
    for byte in dst.iter_mut() {
        *byte = ch;
    }
}

/// Copies data from the source slice to the destination slice.
pub fn memcpy(dst: &mut [u8], src: &[u8]) {
    // Ensure that the slices have the same length to avoid buffer overflow.
    assert_eq!(dst.len(), src.len());

    // Use the copy_nonoverlapping function from the standard library.
    // all right,a little wield,but may work
    unsafe {
        ptr::copy_nonoverlapping(src.as_ptr(), dst.as_mut_ptr(), src.len());
    }
}

/// Compares two strings and returns an ordering.
pub fn strcmp(src: &str, dst: &str) -> core::cmp::Ordering {
    src.cmp(dst)
}

/// Compares two strings up to a specified size and returns an ordering.
pub fn strncmp(src: &str, dst: &str, size: usize) -> core::cmp::Ordering {
    let src_bytes = src.as_bytes().iter().take(size);
    let dst_bytes = dst.as_bytes().iter().take(size);
    src_bytes.cmp(dst_bytes)
}

/// Returns the length of the string.
pub fn strlen(src: &str) -> usize {
    src.len()
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_memset() {
        // OK
        let mut buffer = [0u8; 10];
        memset(&mut buffer, 42);

        assert!(buffer.iter().all(|&byte| byte == 42));
    }

    #[test]
    fn test_memcpy() {
        // OK
        let src = [1, 2, 3, 4, 5];
        let mut dst = [0; 5];

        memcpy(&mut dst, &src);

        assert_eq!(src, dst);
    }

    #[test]
    fn test_strcmp() {
        // Ok
        assert_eq!(strcmp("abc", "abc"), core::cmp::Ordering::Equal);
        assert_eq!(strcmp("abc", "abd"), core::cmp::Ordering::Less);
        assert_eq!(strcmp("abc", "abb"), core::cmp::Ordering::Greater);
    }

    #[test]
    fn test_strncmp() {
        // OK
        assert_eq!(strncmp("abc", "abc", 2), core::cmp::Ordering::Equal);
        assert_eq!(strncmp("abc", "abd", 2), core::cmp::Ordering::Equal);
        assert_eq!(strncmp("abc", "abb", 3), core::cmp::Ordering::Greater);
        assert_eq!(strncmp("abc", "ab", 5), core::cmp::Ordering::Greater);
        assert_eq!(strncmp("abc", "ab", 0), core::cmp::Ordering::Equal);
        assert_eq!(strncmp("abc", "ac", 2), core::cmp::Ordering::Less);
    }

    #[test]
    fn test_strlen() {
    // OK
        assert_eq!(strlen("abc"), 3);
        assert_eq!(strlen(""), 0);
    }
}

